home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / tde10src.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1991-06-05  |  26KB  |  842 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - hardware dependent module
  10.  * Purpose: This file contains all the code that needs to be different on
  11.  *           different hardware.
  12.  * File:    hwibm.c
  13.  * Author:  Douglas Thomson
  14.  * System:  This particular version is for the IBM PC and close compatibles.
  15.  *           It write directly to video RAM, so it is faster than other
  16.  *           techniques, but will cause "snow" on most CGA cards. See the
  17.  *           file "hwibmcga.c" for a version that avoids snow.
  18.  *          The compiler is Turbo C 2.0, using one of the large data memory
  19.  *           models.
  20.  * Date:    October 10, 1989
  21.  * Notes:   This module has been kept as small as possible, to facilitate
  22.  *           porting between different systems.
  23.  */
  24. /*********************  end of original comments   ********************/
  25.  
  26.  
  27. /*
  28.  * These routines were rewritten for Microsoft C.  They are pretty much system
  29.  * dependent and pretty much Microsoft C dependent.  I also renamed this file
  30.  * "main.c" - easier to find the main function.
  31.  *
  32.  * New editor name:  tde, the Thomson-Davis Editor.
  33.  * Author:           Frank Davis
  34.  * Date:             June 5, 1991
  35.  *
  36.  * This modification of Douglas Thomson's code is released into the
  37.  * public domain, Frank Davis.  You may distribute it freely.
  38.  */
  39.  
  40. char *greatest_composer_ever = "W. A. Mozart, 1756-1791";
  41.  
  42. #include "tdestr.h"     /* tde types */
  43. #include "common.h"
  44. #include "define.h"
  45. #include "default.h"
  46. #include "help.h"
  47. #include "tdefunc.h"
  48. #include "version.h"    /* current version number */
  49. #include <dos.h>        /* for renaming files */
  50. #ifdef __TURBOC__
  51.    #include <dir.h>        /* for searching the current path */
  52. #endif
  53. #include <bios.h>       /* for direct BIOS keyboard input */
  54. #if defined( __TURBOC__ )
  55.    #include <alloc.h>      /* for memory allocation */
  56. #elif defined( __MSC__ )
  57.    #include <malloc.h>      /* for memory allocation */
  58. #endif
  59. #include <io.h>         /* for file attribute code */
  60. #include <fcntl.h>      /* open flags */
  61. #if defined( __MSC__ )
  62.    #include <bios.h>
  63.    #include <errno.h>
  64.    #include <sys\types.h>   /* S_IWRITE etc */
  65. #endif
  66. #include <sys\stat.h>   /* S_IWRITE etc */
  67.  
  68. #if defined( __MSC__ )
  69. void (interrupt far *old_control_c)( void );  /* variable for old CNTL-C */
  70. #endif
  71.  
  72. int full_screen_buffer[2000];  /* 25 lines * 80 columns = 2000 characters */
  73.                                /* (make it an int for the attribute)      */
  74.  
  75. /*
  76.  * original control-break checking flag
  77.  */
  78. static int s_cbrk;
  79.  
  80. /*
  81.  * Name:    main
  82.  * Purpose: To do any system dependent command line argument processing,
  83.  *           and then call the main editor function.
  84.  * Date:    October 10, 1989
  85.  * Passed:  argc:   number of command line arguments
  86.  *          argv:   text of command line arguments
  87.  */
  88. void main( argc, argv )
  89. int argc;
  90. char *argv[];
  91. {
  92. #if defined( __MSC__ )
  93.    union REGS inregs, outregs;
  94. #endif
  95.  
  96.    /*
  97.     * trap control-break to make it harmless, and turn checking off
  98.     */
  99. #if defined( __MSC__ )
  100.    inregs.h.ah = 0x33;
  101.    inregs.h.al = 0;
  102.    intdos( &inregs, &outregs );
  103.    s_cbrk = outregs.h.dl;
  104.    old_control_c = _dos_getvect( 0x23 );
  105.    _dos_setvect( 0x23, harmless );
  106.    inregs.h.ah = 0x33;
  107.    inregs.h.al = 1;
  108.    inregs.h.dl = 0;
  109.    intdos( &inregs, &outregs );
  110. #else
  111.    s_cbrk = getcbrk( );
  112.    ctrlbrk( harmless );
  113.    setcbrk( 0 );
  114. #endif
  115.  
  116.    editor( argc, argv );
  117. }
  118.  
  119.  
  120. /*
  121.  * Name:    error
  122.  * Purpose: To report an error, and usually make the user type <ESC> before
  123.  *           continuing.
  124.  * Date:    June 5, 1991
  125.  * Passed:  kind:   an indication of how serious the error was:
  126.  *                      WARNING: error, but editor can continue after <ESC>
  127.  *                      FATAL:   abort the editor!
  128.  *          message: string to be printed
  129.  * Notes:   Show dummy the message and ask for <ESC> if needed.
  130.  */
  131. void error( kind, line, message )
  132. int kind, line;
  133. char *message;
  134. {
  135. char buff[MAX_COLS+2];    /* somewhere to store error before printing */
  136. int c;                  /* character entered by user to continue */
  137. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  138.  
  139.    /*
  140.     * tell the user what kind of an error it is
  141.     */
  142.    switch (kind) {
  143.       case FATAL:
  144.          strcpy( buff, "Fatal error: " );
  145.          break;
  146.      case WARNING:
  147.          strcpy( buff, "Warning: " );
  148.          break;
  149.    }
  150.  
  151.    /*
  152.     * prepare the error message itself
  153.     */
  154.    strcat( buff, message );
  155.  
  156.    /*
  157.     * tell the user how to continue editing if necessary
  158.     */
  159.    if (kind == WARNING)
  160.       strcat( buff, ": type <ESC>" );
  161.  
  162.    /*
  163.     * output the error message
  164.     */
  165.    save_screen_line( 0, line, line_buff );
  166.    set_prompt( buff, line );
  167.  
  168.    if (kind == FATAL) {
  169.       /*
  170.        * no point in making the user type <ESC>, since the program is
  171.        *  about to abort anyway...
  172.        */
  173.       terminate( );
  174.       exit( 1 );
  175.    } else {
  176.       /*
  177.        * If necessary, force the user to acknowledge the error by
  178.        *  typing <ESC> (or ^U).
  179.        * This prevents any extra commands the user has entered from
  180.        *  causing problems after an error may have made them inappropriate.
  181.        */
  182.  
  183.       c = (c=getch()) != 0 ? c : getch() | 0x100;
  184.       while (key_func[c].func != AbortCommand)
  185.          c = (c=getch()) != 0 ? c : getch() | 0x100;
  186.    }
  187.    restore_screen_line( 0, line, line_buff );
  188. }
  189.  
  190. /*
  191.  * Name:    harmless
  192.  * Purpose: To process control-break by ignoring it, so that the editor is
  193.  *           not aborted.
  194.  * Date:    June 5, 1991
  195.  */
  196. #if defined( __MSC__ )
  197. int interrupt far harmless( void )
  198. #else
  199. static int harmless(void)
  200. #endif
  201. {
  202.     return( 1 );   /* ignore */
  203. }
  204.  
  205.  
  206. /*
  207.  * Name:    hw_xygoto
  208.  * Purpose: To move the cursor to a new position on the screen.
  209.  * Date:    October 10, 1989
  210.  * Passed:  [g_display.line]: the required line
  211.  *          [g_display.col]:  the required column
  212.  */
  213. void hw_xygoto( )
  214. {
  215. #if defined( __MSC__ )
  216.    union REGS inregs, outregs;
  217.  
  218.    inregs.h.ah = 2;
  219.    inregs.h.bh = 0;
  220.    inregs.h.dh = g_display.line;
  221.    inregs.h.dl = g_display.col;
  222.    int86( 0x10, &inregs, &outregs );
  223. #else
  224.    gotoxy( g_display.col+1, g_display.line+1 );
  225. #endif
  226. }
  227.  
  228. /*
  229.  * Name:    hw_terminate
  230.  * Purpose: To restore the terminal to a safe state prior to leaving the
  231.  *           editor.
  232.  * Date:    October 10, 1989
  233.  */
  234. void hw_terminate( )
  235. {
  236. #if defined( __MSC__ )
  237.    union REGS inregs, outregs;
  238. #endif
  239.  
  240.    force_blank( );
  241. #if defined( __MSC__ )
  242.    g_display.line = 0;
  243.    g_display.col  = 0;
  244.    hw_xygoto( );
  245. #else
  246.    gotoxy( g_display.ncols, g_display.nlines );
  247.    textattr( g_display.normal );
  248. #endif
  249.    putch( ' ' );
  250.    printf( "tde version %s for IBM PC", VERSION );
  251.  
  252.    /*
  253.     * restore control-break checking
  254.     */
  255. #if defined( __MSC__ )
  256.    _dos_setvect( 0x23, old_control_c );
  257.    inregs.h.ah = 0x33;
  258.    inregs.h.al = 1;
  259.    inregs.h.dl = s_cbrk;
  260.    intdos( &inregs, &outregs );
  261. #else
  262.    setcbrk( s_cbrk );
  263. #endif
  264. }
  265.  
  266. /*
  267.  * Name:    hw_initialize
  268.  * Purpose: To initialize the display ready for editor use.
  269.  * Date:    June 5, 1991
  270.  */
  271. void hw_initialize( )
  272. {
  273. #if defined( __MSC__ )
  274.    struct vcfg cfg;
  275. #else
  276.    struct text_info buff; /* for discovering display type */
  277. #endif
  278. unsigned paragraphs;
  279. long space;            /* amount of memory to use */
  280.  
  281.    /*
  282.     * set up screen size
  283.     */
  284.    g_display.ncols     = MAX_COLS;
  285.    g_display.nlines    = MAX_LINES - 1;
  286.    g_display.mode_line = MAX_LINES;
  287.    g_display.line_length = MAX_LINE_LENGTH;
  288.  
  289.    /*
  290.     * work out what kind of display is in use, and set attributes and
  291.     *  display address accordingly. Note that this will only work with
  292.     *  close IBM compatibles.
  293.     */
  294.  
  295.    video_config( &cfg );
  296.    g_display.display_address = (char far *)cfg.videomem;
  297.    if (cfg.color == FALSE) {
  298.       g_display.head_color  = HERC_REVERSE;
  299.       g_display.text_color  = HERC_NORMAL;
  300.       g_display.mode_color  = HERC_REVERSE;
  301.       g_display.block_color = HERC_REVERSE;
  302.       g_display.message_color = HERC_HIGH;
  303.       g_display.help_color  = HERC_NORMAL;
  304.    } else {
  305.       if (cfg.mode == MONO_80) {
  306.          g_display.head_color = LCD_REVERSE;
  307.          g_display.text_color = LCD_NORMAL;
  308.          g_display.mode_color = LCD_REVERSE;
  309.          g_display.block_color = LCD_HIGH;
  310.          g_display.message_color = LCD_HIGH;
  311.          g_display.help_color = LCD_HIGH;
  312.       } else {
  313.          g_display.head_color = COLOR_HEAD;
  314.          g_display.text_color = COLOR_TEXT;
  315.          g_display.mode_color = COLOR_MODE;
  316.          g_display.block_color = COLOR_BLOCK;
  317.          g_display.message_color = COLOR_MESSAGE;
  318.          g_display.help_color = COLOR_HELP;
  319.       }
  320.    }
  321.  
  322.    /*
  323.     * all the available memory for the text buffer
  324.     */
  325. #if defined( __MSC__ )
  326.    _dos_allocmem( 0xffff, ¶graphs );
  327.    space = paragraphs;
  328.    space = space << 4;
  329.    /*
  330.     * if using Microsoft C, allocate all available memory.
  331.     */
  332. /*   if (space > 7000l)
  333.       space = 7000l;   */
  334.    if (space <= 0)
  335.       return;
  336. #else
  337.    space = farcoreleft() - 30000L;
  338. #endif
  339.  
  340. #if defined( __MSC__ )
  341.    if ((g_status.start_mem = (text_ptr)halloc( space, sizeof( char ))) == NULL)
  342.       error( FATAL, g_display.nlines, "out of memory???" );
  343. #else
  344.    if ((g_status.start_mem = farmalloc(space)) == NULL)
  345.       error( FATAL, g_display.nlines, "out of memory???" );
  346. #endif
  347.    g_status.max_mem = addltop( space, g_status.start_mem );
  348. }
  349.  
  350.  
  351. /*
  352.  *   Video BIOS Data Areas
  353.  *   The BIOS routines maintain several dynamic variables in an area of
  354.  *   memory called the Video Display Data Area.  The following contains a
  355.  *   summary of these variables' addresses, their symbolic names, and
  356.  *   their contents.  All addresses are relative to the 0x0000h segment.
  357.  *
  358.  *   Address  Name           Type   Description
  359.  *   0x0449   CRT_MODE       Byte   Current BIOS video number
  360.  *   0x044a   CRT_COLS       Word   Number of displayed character columns
  361.  *   0x044c   CRT_LEN        Word   Size of video buffer in bytes
  362.  *   0x044e   CRT_START      Word   Offset of start of video buffer
  363.  *   0x0450   CURSOR_POSN    Word   Array of eight words containing the cursor
  364.  *                                    position for each of eight possible
  365.  *                                    video pages.  The high-order byte of
  366.  *                                    each word contains the character row,
  367.  *                                    the low-order byte the character column
  368.  *   0x0460   CURSOR_MODE    Word   Starting and ending lines for alphanumeric
  369.  *                                    cursor.  The high-order byte contains
  370.  *                                    the starting (top) line; the low-order
  371.  *                                    byte contains the ending (bottom) line
  372.  *   0x0462   ACTIVE_PAGE    Byte   Currently displayed video page number
  373.  *   0x0463   ADDR_6845      Word   I/O port address of CRT Controller's
  374.  *                                    Address register (3B4h for mono;
  375.  *                                    3D4h for color)
  376.  *   0x0465   CRT_MODE_SET   Byte   Current value for Mode Control register
  377.  *                                    (3B8h on MDA, 3D8h on CGA).  On the
  378.  *                                    EGA and VGA, the value emulates those
  379.  *                                    used on the MDA and CGA.
  380.  *   0x0466   CRT_PALETTE    Byte   Current value for the CGA Color Select
  381.  *                                    register (3D9h).  On the EGA and VGA,
  382.  *                                    the value emulates those used on the
  383.  *                                    MDA and CGA.
  384.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  385.  *   0x0485   POINTS         Word   Height of character matrix
  386.  *   0x0487   INFO           Byte   EGA and VGA display data
  387.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  388.  *   0x0489   flags          Byte   Miscellaneous flags
  389.  *   0x048A   DCC            Byte   Display Combination Code
  390.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  391.  *
  392. */
  393. void video_config( struct vcfg *cfg )
  394. {
  395. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  396.  
  397. struct LOWMEMVID
  398. {
  399.    char     vidmode;           /* 0x449 */
  400.    unsigned scrwid;            /* 0x44A */
  401.    unsigned scrlen;            /* 0x44C */
  402.    unsigned scroff;            /* 0x44E */
  403.    struct   LOCATE
  404.    {
  405.       unsigned char col;
  406.       unsigned char row;
  407.    } csrpos[8];                /* 0x450 */
  408.    struct   CURSIZE
  409.    {
  410.       unsigned char end;
  411.       unsigned char start;
  412.    } csrsize;                  /* 0x460 */
  413.    char      page;             /* 0x462 */
  414.    unsigned  addr_6845;        /* 0x463 */
  415.    char      crt_mode_set;     /* 0x465 */
  416.    char      crt_palette[30];  /* 0x466 */
  417.    char      rows;             /* 0x484 */
  418.    unsigned  points;           /* 0x485 */
  419.    char      ega_info;         /* 0x487 */
  420.    char      info_3;           /* 0x488 */
  421. } vid;
  422. struct LOWMEMVID _far *pvid = &vid;
  423. #pragma pack( )    /* revert to previously defined pack pragma. */
  424.  
  425. union REGS in, out;
  426.  
  427.    /* Move system information into uninitialized structure variable. */
  428.    movedata( 0, 0x449, FP_SEG( pvid ), FP_OFF( pvid ), sizeof( vid ) );
  429.  
  430.    in.h.ah =  0x12;
  431.    in.h.bl =  0x10;
  432.    int86( VIDEO_INT, &in, &out );
  433.    if (out.h.bl == 0x10) {         /* EGA */
  434.        if (vid.addr_6845 == 0x3D4)
  435.           cfg->rescan = TRUE;
  436.        else
  437.           cfg->rescan = FALSE;
  438.    } else {
  439.       if ((vid.ega_info & 0x08) && (vid.addr_6845 == 0x3D4))
  440.          cfg->rescan = TRUE;
  441.       else
  442.          cfg->rescan = FALSE;
  443.    }
  444.    cfg->mode = vid.vidmode;
  445.    if (vid.addr_6845 == 0x3D4) {
  446.       cfg->color = TRUE;
  447.       FP_SEG( cfg->videomem ) = 0xb800;
  448.    } else {
  449.       cfg->color = FALSE;
  450.       FP_SEG( cfg->videomem ) = 0xb000;
  451.    }
  452.    FP_OFF( cfg->videomem ) = 0x0000;
  453. }
  454.  
  455. /*
  456.  * Name:    hw_move
  457.  * Purpose: To move data from one place to another as efficiently as
  458.  *           possible.
  459.  * Date:    October 10, 1989
  460.  * Passed:  dest:   where to copy to
  461.  *          source: where to copy from
  462.  *          number: number of bytes to copy
  463.  * Notes:   moves may be (usually will be) overlapped.  Although we can
  464.  *          move up to 64k-1 bytes at once, unfortunately we can safely
  465.  *          move only 16k bytes at one time.  The pointer checking functions
  466.  *          ensure that a pointer is not within 16k of a segment.
  467.  */
  468. void hw_move( dest, source, number )
  469. text_ptr dest;
  470. text_ptr source;
  471. long number;
  472. {
  473. unsigned long s, d;
  474.  
  475.    s = ptoul( source );
  476.    d = ptoul( dest );
  477.    if (number < 0)
  478.       /*
  479.        * this should never happen...
  480.        */
  481.       error( WARNING, g_display.nlines, "negative move - contact Frank Davis" );
  482.    else if (s == d)
  483.       /*
  484.        * nothing to be done
  485.        */
  486.       ;
  487.    else if (s > d) {
  488.       while (number > 0x4000L) {
  489.          dest = cpf( dest );
  490.          source = cpf( source );
  491.          memmove( (char *)dest, (char *)source, 0x4000 );
  492.          number -= 0x4000L;
  493.          dest = addltop( 0x4000L, dest );
  494.          source = addltop( 0x4000L, source );
  495.       }
  496.       /*
  497.        * now less than 16K is left, so finish off the move
  498.        */
  499.       dest = cpf( dest );
  500.       source = cpf( source );
  501.       memmove( (char *)dest, (char *)source, (unsigned)number );
  502.    } else {
  503.       source = addltop( number, source );
  504.       dest = addltop( number, dest );
  505.       while (number > 0x4000L) {
  506.          dest = cpb( dest );
  507.          source = cpb( source );
  508.          source = addltop( -0x4000L, source );
  509.          dest = addltop( -0x4000L, dest );
  510.          number -= 0x4000L;
  511.          memmove( (char *)dest, (char *)source, 0x4000 );
  512.       }
  513.       source = cpb( source );
  514.       dest = cpb( dest );
  515.       source = addltop( -number, source );
  516.       dest = addltop( -number, dest );
  517.       memmove( (char *)dest, (char *)source, (unsigned)number );
  518.    }
  519. }
  520.  
  521. /*
  522.  * Name:    hw_fattrib
  523.  * Purpose: To determine the current file attributes.
  524.  * Date:    October 17, 1989
  525.  * Passed:  name: name of file to be checked
  526.  * Returns: current read/write/execute etc attributes of the file, or
  527.  *          ERROR if file did not exist etc.
  528.  */
  529. int hw_fattrib( name )
  530. char *name;
  531. {
  532. int rc;
  533.  
  534. #if defined( __MSC__ )
  535.    rc = access( name, EXIST );
  536. #else
  537.    rc = _chmod( name, EXIST );
  538. #endif
  539.    return( rc );
  540. }
  541.  
  542. /*
  543.  * Name:    hw_unlink
  544.  * Purpose: To delete a file, regardless of access modes.
  545.  * Date:    October 17, 1989
  546.  * Passed:  name:   name of file to be removed
  547.  * Returns: OK if file could be removed
  548.  *          ERROR otherwise
  549.  */
  550. int  hw_unlink( name, line )
  551. char *name;
  552. int line;
  553. {
  554. int result;
  555. int rc;
  556. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  557.  
  558.    rc = OK;
  559. #if defined( __MSC__ )
  560.    if ((result = access( name, EXIST )) != -1 && errno != EACCES) {
  561. #else
  562.    if ((result = _chmod( name, EXIST )) != -1 && (result & FA_RDONLY) != 0) {
  563. #endif
  564.       /*
  565.        * file cannot be written
  566.        */
  567.       save_screen_line( 0, line, line_buff );
  568.       set_prompt( "File is write protected! Overwrite anyway? (y/n): ", line );
  569.       if (get_yn( ) != A_YES)
  570.          rc = ERROR;
  571. #if defined( __MSC__ )
  572.       if (rc == OK && chmod( name, S_IWRITE ) == ERROR)
  573.          rc = ERROR;
  574. #else
  575.       if (rc == OK && _chmod( name, 1, 0 ) == ERROR)
  576.          rc = ERROR;
  577. #endif
  578.       restore_screen_line( 0, line, line_buff );
  579.    }
  580.    if (rc == OK)
  581.       rc = unlink( name );
  582.    return( rc );
  583. }
  584.  
  585. /*
  586.  * Name:    write_file
  587.  * Purpose: To write text to a file, eliminating trailing space on the
  588.  *           way.
  589.  * Date:    June 5, 1991
  590.  * Passed:  name:  name of disk file or device
  591.  *          mode:  fopen flags to be used in open
  592.  *          start: first character in text buffer
  593.  *          end:   last character (+1) in text buffer
  594.  *          block: write a file or a marked block
  595.  *          prompt_line: line to display error messages
  596.  * Returns: OK, or ERROR if anything went wrong
  597.  */
  598. int  write_file( name, mode, start, end, block, prompt_line )
  599. char *name;
  600. char *mode;
  601. text_ptr start;
  602. text_ptr end;
  603. int block, prompt_line;
  604. {
  605. FILE *fp;       /* file to be written */
  606. int rc;
  607. char *p, *q;
  608. int len;
  609. int bc, ec, last_c;
  610. file_infos *file;
  611.  
  612.    rc = OK;
  613.    if ((fp = fopen( name, mode )) == NULL)
  614.       rc = ERROR;
  615.    else {
  616.       /*
  617.        * save the file, eliminating trailing space
  618.        */
  619.       start = cpf( start );
  620.       if (block == LINE || block == BLOCK) {
  621.          if (g_status.marked_file == NULL)
  622.             rc = ERROR;
  623.          else if (block == BLOCK) {
  624.             file = g_status.marked_file;
  625.             bc = file->block_bc;
  626.             ec = file->block_ec;
  627.             last_c = ec + 1 - bc;
  628.          }
  629.       }
  630.       p = g_status.line_buff;
  631.       if (rc == OK) {
  632.          for (;ptoul( start ) < ptoul( end );) {
  633.             if (block == NOTMARKED || block == LINE) {
  634.                copy_line( start, prompt_line );
  635.                len = linelen( start );
  636.                if (*(p+len) == CONTROL_Z) {
  637.                   *(p+len) = '\n';
  638.                   *(p+len+1) = CONTROL_Z;
  639.                }
  640.             } else {
  641.                load_buff( p, start, bc, ec, BLOCK );
  642.                *(p+last_c) = '\n';
  643.                *(p+last_c+1) = CONTROL_Z;
  644.                len = last_c;
  645.             }
  646.             for (q=p+len-1; len > 0; len--, q--) {
  647.                if (*q == ' ') {
  648.                   *q = '\n';
  649.                   *(q+1) = CONTROL_Z;
  650.                } else
  651.                   break;
  652.             }
  653.             len = find_CONTROL_Z( p );
  654.             fwrite( p, sizeof( char ), len, fp );
  655.             start = find_next( start );
  656.             if (start == NULL)
  657.                start = end;
  658.          }
  659.          rc = fclose( fp );
  660.       }
  661.    }
  662.    return( rc );
  663. }
  664.  
  665. /*
  666.  * Name:    hw_save
  667.  * Purpose: To save text to a file, eliminating trailing space on the
  668.  *           way.
  669.  * Date:    November 11, 1989
  670.  * Passed:  name:  name of disk file
  671.  *          start: first character in text buffer
  672.  *          end:   last character (+1) in text buffer
  673.  * Returns: OK, or ERROR if anything went wrong
  674.  * Notes:   Trailing space at the very end of the file is NOT removed,
  675.  *           so that a block write of a block of spaces will work.
  676.  *          No error messages are displayed here, so the caller must
  677.  *           both tell the user what is happening, and print an error
  678.  *           message if anything goes wrong.
  679.  *          This function is in the hardware dependent module because
  680.  *           some computers require non-standard open parameters...
  681.  */
  682. int hw_save( name, start, end, block, prompt_line )
  683. char *name;
  684. text_ptr start;
  685. text_ptr end;
  686. int block, prompt_line;
  687. {
  688.    return write_file( name, "w", start, end, block, prompt_line );
  689. }
  690.  
  691. /*
  692.  * Name:    hw_append
  693.  * Purpose: To append text to a file.
  694.  * Date:    November 11, 1989
  695.  * Passed:  name:  name of disk file
  696.  *          start: first character in text buffer
  697.  *          end:   last character (+1) in text buffer
  698.  * Returns: OK, or ERROR if anything went wrong
  699.  * Notes:   No error messages are displayed here, so the caller must
  700.  *           both tell the user what is happening, and print an error
  701.  *           message if anything goes wrong.
  702.  *          This function is in the hardware dependent module because
  703.  *           some computers require non-standard open parameters...
  704.  */
  705. int hw_append( name, start, end, block, prompt_line )
  706. char *name;
  707. text_ptr start;
  708. text_ptr end;
  709. int block, prompt_line;
  710. {
  711.    return write_file( name, "a", start, end, block, prompt_line );
  712. }
  713.  
  714. /*
  715.  * Name:    hw_print
  716.  * Purpose: To print text to a printer.
  717.  * Date:    November 11, 1989
  718.  * Passed:  start: first character in text buffer
  719.  *          end:   last character (+1) in text buffer
  720.  * Returns: OK, or ERROR if anything went wrong
  721.  * Notes:   This function is in the hardware dependent module because
  722.  *           some computers require non-standard open parameters...
  723.  */
  724. int hw_print( start, end, block, prompt_line )
  725. text_ptr start;
  726. text_ptr end;
  727. int block, prompt_line;
  728. {
  729.    return write_file( "PRN", "a", start, end, block, prompt_line );
  730. }
  731.  
  732. /*
  733.  * Name:    hw_load
  734.  * Purpose: To load a file into the text buffer.
  735.  * Date:    November 11, 1989
  736.  * Passed:  name:  name of disk file
  737.  *          start: first character in text buffer
  738.  *          limit: last available character in text buffer
  739.  *          end:   last character of file in text buffer
  740.  * Returns: OK, or ERROR if anything went wrong
  741.  * Notes:   All error messages are displayed here, so the caller should
  742.  *           neither tell the user what is happening, nor print an error
  743.  *           message if anything goes wrong.
  744.  *          This function is in the hardware dependent module because
  745.  *           some computers require non-standard open parameters...
  746.  */
  747. int hw_load( name, start, limit, end, line )
  748. char *name;
  749. text_ptr start;
  750. text_ptr limit;
  751. text_ptr *end;
  752. int line;
  753. {
  754. int fd;         /* file being read */
  755. int length;     /* number of bytes actually read */
  756. int rc;
  757. char buff[MAX_COLS+2];
  758.  
  759.    /*
  760.     * try reading the file
  761.     */
  762.    rc = OK;
  763.    if ((fd = open( name, O_RDONLY )) == ERROR) {
  764.       combine_strings( buff, "File '", name, "'not found" );
  765.       error( WARNING, line, buff );
  766.       rc = ERROR;
  767.    } else {
  768.       /*
  769.        * read the entire file, without going past end of buffer.
  770.        * Note that this means a file that is within 1K of the limit
  771.        *  will not be accepted.  length set to a number > 0 for first loop
  772.        */
  773.       limit = addltop( -1024, limit );
  774.       start = cpf( start );
  775.       for (length=1; rc != ERROR && length > 0;) {
  776.          if (ptoul( start ) >= ptoul( limit )) {
  777.             combine_strings( buff, "file '", name, "'too big" );
  778.             error( WARNING, line, buff );
  779.             rc = ERROR;
  780.          } else {
  781.             if ((length = read( fd, (char *)start, 1024 )) == ERROR) {
  782.                combine_strings( buff, "error reading file '", name, "'" );
  783.                error( WARNING, line, buff );
  784.                rc = ERROR;
  785.             } else
  786.                start = addltop( length, start );
  787.             start = cpf( start );
  788.          }
  789.       }
  790.       /*
  791.        * close the file and report the final character in the buffer
  792.        */
  793.       close( fd );
  794.       *end = start;
  795.    }
  796.    return( rc );
  797. }
  798.  
  799.  
  800. /*
  801.  * Name:    get_help
  802.  * Purpose: save the screen and display key definitions
  803.  * Date:    June 5, 1991
  804.  * Passed:  window: information allowing access to the current window
  805.  */
  806. void get_help( window )
  807. windows *window;
  808. {
  809. char *help;
  810. int line;
  811.  
  812.    xygoto( -1, -1 );
  813.    memcpy( full_screen_buffer, g_display.display_address, 4000 );
  814.    help = help_screen[0];
  815.    for (line=0; help != NULL; ) {
  816.       s_output( help, line, 0, g_display.help_color );
  817.       help = help_screen[++line];
  818.    }
  819.    line = (line = getch()) != 0 ? 0 : getch();
  820.    memcpy( g_display.display_address, full_screen_buffer, 4000 );
  821. }
  822.  
  823.  
  824. /*
  825.  * Name:    show_credits
  826.  * Purpose: display authors
  827.  * Date:    June 5, 1991
  828.  * Passed:  window: information allowing access to the current window
  829.  */
  830. void show_credits( )
  831. {
  832. char *credit;
  833. int line;
  834.  
  835.    xygoto( -1, -1 );
  836.    credit = credit_screen[0];
  837.    for (line=0; credit != NULL; ) {
  838.       s_output( credit, line+2, 11, g_display.text_color );
  839.       credit = credit_screen[++line];
  840.    }
  841. }
  842.